<?php
/**
 * @package		简易CMS
 * @subpackage	系统核心处理类
 * @version		$Id: class_core.php 25 2012-08-29 17:55:19Z htmambo@gmail.com $
 * @author		Hoping
 * @copyright	Copyright (C) 2010 Hoping Software Studio.
 */

define('IN_JYCMS', true);
class cmsCore {
	/**
	 *
	 * @var db_mysql
	 */
	var $db = null;
	/**
	 *
	 * @var cmsSession
	 */
	var $session = null;
	var $var = array();
	var $cachelist = array();
	var $init_setting = true;
	var $init_user = true;
	var $init_session = true;
	var $init_cron = true;
	var $init_misc = true;
	var $initated = false;
	/**
	 *
	 * @var cmsLanguage
	 */
	var $lang = false;
	var $superglobal = array(
		'GLOBALS' => 1,
		'_GET' => 1,
		'_POST' => 1,
		'_REQUEST' => 1,
		'_COOKIE' => 1,
		'_SERVER' => 1,
		'_ENV' => 1,
		'_FILES' => 1,
	);

	/**
	 * 系统初始化
	 *
	 * @return core
	 */
	public static function &instance() {
		static $object;
		if (empty($object)) {
			$object = new cmsCore();
		}
		return $object;
	}

	function cmsCore() {
		/**
		 * 将所有的文件读 写的操作都放到此类中，以便做效率统计
		 */
		$this->_init_env();
		$this->_init_config();
		$this->_init_input();
		$this->_init_output();
	}

	/**
	 * 系统初始化
	 */
	function init() {
		if (!$this->initated) {
			$this->_init_db();
			$this->_init_user();
			$this->_init_session();
			$this->_init_setting();
			$this->_init_cron();
			$this->_init_misc();
		}
		$this->initated = true;
	}

	/**
	 * 初始化系统运行环境变量
	 * @global 数组 $_G
	 */
	function _init_env() {
		if (phpversion() < '5.3.0') {
			set_magic_quotes_runtime(0);
		}

		define('TIMESTAMP', time());
		$this->timezone_set();
		define('ROOT_PATH', substr(dirname(__FILE__), 0, -12));
		define('MAGIC_QUOTES_GPC', function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc());
		define('ICONV_ENABLE', function_exists('iconv'));
		//检测并加载核心函数包
		if (!defined('CMS_FUNCTION') && !@include(ROOT_PATH . './source/function/function_core.php')) {
			exit('function_core.php is missing');
		}
		//加载文件处理函数包
		include_once libfile('class/files');
		//检测内存限制
		if (function_exists('ini_get')) {
			$memorylimit = @ini_get('memory_limit');
			if ($memorylimit && return_bytes($memorylimit) < 33554432 && function_exists('ini_set')) {
				ini_set('memory_limit', '128m');
			}
		}

		define('IS_ROBOT', checkrobot());
		//如果是蜘蛛的话，就不要更新SESSION了
		if(IS_ROBOT) $this->init_session = false;
		//简单的防范一下
		foreach ($GLOBALS as $key => $value) {
			if (!isset($this->superglobal[$key])) {
				$GLOBALS[$key] = null;
				unset($GLOBALS[$key]);
			}
		}

		global $_G;
		$_G = array(
			'custom' => array(
				'style' => array(),
				'script' => array(),
				'footer' =>''
			),
			'uid' => 0,
			'username' => '',
			'adminid' => 0,
			'groupid' => 1,
			'sid' => '',
			'formhash' => '',
			'timestamp' => TIMESTAMP,
			'starttime' => dmicrotime(),
			'clientip' => $this->_get_client_ip(),
			'referer' => '',
			'charset' => '',
			'gzipcompress' => '',
			'authkey' => '',
			'timenow' => array(),
			'PHP_SELF' => '',
			'siteurl' => '',
			'siteroot' => '',
			'config' => array(),
			'setting' => array(),
			'member' => array(),
			'group' => array(),
			'cookie' => array(),
			'style' => array(),
			'cache' => array(),
			'session' => array(),
			'lang' => array(),
			'block' => array(),
			'article' => array(),
		);
		$_G['PHP_SELF'] = htmlspecialchars($_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['PHP_SELF']);
		$_G['basefilename'] = basename($_G['PHP_SELF']);
		$_G['siteurl'] = htmlspecialchars('http://' . $_SERVER['HTTP_HOST'] . preg_replace("/\/+(api)?\/*$/i", '', substr($_G['PHP_SELF'], 0, strrpos($_G['PHP_SELF'], '/'))) . '/');
		$_G['siteroot'] = substr($_G['PHP_SELF'], 0, -strlen($_G['basefilename']));
		if (defined('SUB_DIR')) {
			$_G['siteurl'] = str_replace(SUB_DIR, '/', $_G['siteurl']);
			$_G['siteroot'] = str_replace(SUB_DIR, '/', $_G['siteroot']);
		}
		$this->var = & $_G;
	}

	function _init_input() {
		global $_G;
		if (isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_COOKIE['GLOBALS']) || isset($_FILES['GLOBALS'])) {
			exit('Your current access request which contains illegal characters, has been rejected by the system');
		}
		if (!empty($_GET['rewrite'])) {
			$query_string = '?option='.$_GET['option'];
			$param = explode('/', $_GET['rewrite']);
			//$query_string .= $_GET['option'] = str_replace('.php', '', $param[0]);
			//array_shift($param);
			$paramc = count($param);
			for ($i = 0; $i < $paramc; $i+=2) {
				$this->var['gp_'.$param[$i]] = $_REQUEST[$param[$i]] = $_GET[$param[$i]] = $param[$i + 1];
				$query_string .= '&' . $param[$i] . '=' . $param[$i + 1];
			}
			unset($_GET['rewrite']);
			unset($_REQUEST['rewrite']);
			$_SERVER['QUERY_STRING'] = $query_string;
			unset($param, $paramc, $query_string);
		}
		if (!MAGIC_QUOTES_GPC) {
			$_GET = daddslashes($_GET);
			$_POST = daddslashes($_POST);
			$_COOKIE = daddslashes($_COOKIE);
			$_FILES = daddslashes($_FILES);
		}
		//COOKIE处理
		$prelength = strlen($_G['config']['cookie']['cookiepre']);
		foreach ($_COOKIE as $key => $val) {
			if (substr($key, 0, $prelength) == $_G['config']['cookie']['cookiepre']) {
				$this->var['cookie'][substr($key, $prelength)] = $val;
			}
		}

		$_GET['diy'] = empty($_GET['diy']) ? '' : $_GET['diy'];

		//处理GET、POST值
		foreach (array_merge($_POST, $_GET) as $k => $v) {
			if($k == 'option') $v = str_replace('.php', '', $v);
			$this->var['gp_' . $k] = $v;
		}
		$this->var['option'] = empty($this->var['gp_option'])?'portal':htmlspecialchars($this->var['gp_option']);
		$this->var['task'] = empty($this->var['gp_task']) ? '' : htmlspecialchars($this->var['gp_task']);
		$this->var['inajax'] = empty($this->var['gp_inajax']) ? 0 : ($_SERVER['REQUEST_METHOD'] == 'GET' && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' || $_SERVER['REQUEST_METHOD'] == 'POST' ? 1 : 0);
		$this->var['page'] = empty($this->var['gp_page']) ? 1 : max(1, intval($this->var['gp_page']));
		$this->var['sid'] = $this->var['cookie']['sid'] = isset($this->var['cookie']['sid']) ? htmlspecialchars($this->var['cookie']['sid']) : '';
	}

	/**
	 * 初始化系统配置
	 * @global cmsLanguage $cmsLang
	 * @global string $lang
	 */
	function _init_config() {
		global $_G;
		$_config = array();
		@include ROOT_PATH . './config/config_global.php';
		if (empty($_config)) {
			if (!file_exists(ROOT_PATH . './data/install.lock')) {
				header('location: install');
				exit;
			} else {
				exit('The system config file is not found!');
			}
		}
		if (empty($_config['security']['authkey'])) {
			$_config['security']['authkey'] = md5($_config['cookie']['cookiepre'] . $_config['db']['dbname']);
		}
		if ($_config['debug'] === 1) {
			define('CMS_DEBUG', true);
			error_reporting(E_ALL ^ E_NOTICE);
		} else {
			error_reporting(0);
		}

		define('STATICURL', !empty($_config['output']['staticurl']) ? $_config['output']['staticurl'] : $_G['siteurl'].'static/');
		$this->var['staticurl'] = STATICURL;

		$_G['config'] = & $_config;
		//$this->var['authkey'] = md5($_config['security']['authkey'] . $_SERVER['HTTP_USER_AGENT']);
		//由于swfUpload传递过来的HTTP_USER_AGENT被自定义了，所以这里就不能使用其做为参数了
		$this->var['authkey'] = md5($_config['security']['authkey']);
		include_once libfile('class/language');
		global $cmsLang, $lang;
		if(defined('IN_ADMINCP')) $lang = 'zh-CN';
		else {
			$lang = $_config['output']['language'];
			if (!$lang)
				$lang = 'zh-CN';
		}
		$cmsLang = new cmsLanguage($lang);
		$this->lang = & $cmsLang;
		$this->lang->load();
		$_G['jslang'] = $this->lang->_strings['JSLANG'];
		$_G['jslang']['searchtips'] = $this->lang->_strings['ENTER CONTENT'];
	}

	/**
	 * 初始化系统输出
	 */
	function _init_output() {
		global $_G;
		if ($_G['config']['security']['urlxssdefend'] && $_SERVER['REQUEST_METHOD'] == 'GET' && !empty($_SERVER['REQUEST_URI'])) {
			$temp = urldecode($_SERVER['REQUEST_URI']);
			if (strpos($temp, '<') !== false || strpos($temp, '"') !== false) {
				system_error('Your current access request which contains illegal characters, has been rejected by the system');
			}
		}
		$allowgzip = $_G['config']['output']['gzip'] && empty($this->var['inajax']) && $this->var['mod'] != 'attachment' && function_exists('ob_gzhandler');
		setglobal('gzipcompress', $allowgzip);
		ob_start($allowgzip ? 'ob_gzhandler' : null);

		setglobal('charset', $_G['config']['output']['charset']);
		define('CHARSET', $_G['config']['output']['charset']);
		if(!isset($_GET['task'])) $_GET['task'] = '';
		if ($_G['config']['output']['forceheader'] && $_GET['task']!=='img' && !isset($_GET['inajax'])) {
			@header('Content-Type: text/html; charset=' . CHARSET);
		}
	}

	/**
	 * 不允许蜘蛛继续爬行
	 */
	function reject_robot() {
		if (IS_ROBOT) {
			exit(header("HTTP/1.1 403 Forbidden"));
		}
	}

	/**
	 * 获取当前用户的来访IP地址
	 * @return IP地址
	 */
	function _get_client_ip() {
		$ip = $_SERVER['REMOTE_ADDR'];
		if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
			$ip = $_SERVER['HTTP_CLIENT_IP'];
		} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
			foreach ($matches[0] AS $xip) {
				if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
					$ip = $xip;
					break;
				}
			}
		}
		return $ip;
	}

	/**
	 * 初始化数据库引擎
	 */
	function _init_db() {
		global $db, $_G;
		if (empty($db)) $db = new db_mysql();
		$this->db = & $db;
		$this->db->set_config($_G['config']['db']);
		$this->db->connect();
		robotlog();
	}

	/**
	 * 初始化登录session
	 */
	function _init_session() {

		$this->session = new cmsSession();

		if ($this->init_session) {
			$this->session->init($this->var['cookie']['sid'], $this->var['clientip'], $this->var['uid']);
			$this->var['sid'] = $this->session->sid;
			$this->var['session'] = $this->session->var;

			if ($this->var['sid'] != $this->var['cookie']['sid']) {
				dsetcookie('sid', $this->var['sid'], 86400);
			}

			if ($this->session->isnew) {
				if (ipbanned($this->var['clientip'])) {
					$this->session->set('groupid', 6);
				}
			}

			if ($this->session->get('groupid') == 6) {
				$this->var['member']['groupid'] = 6;
				bannedmsg('Sorry, you can not access the site!');
			}


			if ($this->var['uid'] && ($this->session->isnew || ($this->session->get('lastactivity') + 600) < TIMESTAMP)) {

				$this->session->set('lastactivity', TIMESTAMP);

				if ($this->session->isnew) {
					DB::update('common_member', array('lastip' => $this->var['clientip'], 'lastvisit' => TIMESTAMP), "uid='" . $this->var['uid'] . "'");
				}
			}
		}
	}

	/**
	 * 初始化当前用户
	 */
	function _init_user() {

		if ($this->init_user) {
			if ($auth = getglobal('auth', 'cookie')) {
				$auth = daddslashes(explode("\t", authcode($auth, 'DECODE')));
			} elseif (isset($_POST['authcode'])){
				$auth = daddslashes(explode("\t", authcode($_POST['authcode'], 'DECODE')));
			}
			list($mainframe_pw, $login_uid) = empty($auth) || count($auth) < 2 ? array('', '') : $auth;

			if ($login_uid) {
				$user = getuserbyuid($login_uid);
			}

			if (!empty($user) && $user['password'] == $mainframe_pw) {
				$this->var['member'] = $user;
			} else {
				$user = array();
				$this->_init_guest();
			}

			if ($this->var['member']['groupid'])
				$this->cachelist[] = 'usergroup_' . $this->var['member']['groupid'];
			if ($user && $user['adminid'] > 0 && $user['groupid'] != $user['adminid']) {
				$this->cachelist[] = 'admingroup_' . $this->var['member']['adminid'];
			}
		} else {
			$this->_init_guest();
		}

		if (empty($this->var['cookie']['lastvisit'])) {
			$this->var['member']['lastvisit'] = TIMESTAMP - 3600;
			dsetcookie('lastvisit', TIMESTAMP - 3600, 86400 * 30);
		} else {
			$this->var['member']['lastvisit'] = $this->var['cookie']['lastvisit'];
		}
		setglobal('useremail', getglobal('email', 'member'));
		setglobal('uid', getglobal('uid', 'member'));
		setglobal('username', addslashes(getglobal('username', 'member')));
		setglobal('adminid', getglobal('adminid', 'member'));
		setglobal('groupid', getglobal('groupid', 'member'));
	}

	/**
	 * 初始化游客信息
	 */
	function _init_guest() {
		setglobal('member', array('uid' => 0, 'username' => '', 'adminid' => 0, 'groupid' => 7, 'credits' => 0, 'timeoffset' => 9999));
	}

	/**
	 * 初始化系统计划任务
	 */
	function _init_cron() {
		if ($this->init_cron && $this->init_setting) {
			if ($this->var['cache']['cronnextrun'] <= TIMESTAMP) {
				cmsCron::run();
			}
		}
	}

	function _init_misc() {
		if (!$this->init_misc) {
			return false;
		}
		if ($this->init_setting && $this->init_user) {
			if (!isset($this->var['member']['timeoffset']) || $this->var['member']['timeoffset'] == 9999 || $this->var['member']['timeoffset'] === '') {
				$this->var['member']['timeoffset'] = $this->var['setting']['timeoffset'];
			}
		}

		$timeoffset = $this->init_setting ? $this->var['member']['timeoffset'] : $this->var['setting']['timeoffset'];
		$this->var['timenow'] = array(
			'time' => dgmdate(TIMESTAMP, 'H:i:s'),
			'year' => dgmdate(TIMESTAMP, 'Y'),
			'month' => dgmdate(TIMESTAMP, 'm'),
			'day' => abs(substr(dgmdate(TIMESTAMP, 'd'), -2)),
			'week' => dgmdate(TIMESTAMP, 'D'),
			'offset' => $timeoffset >= 0 ? ($timeoffset == 0 ? '' : '+' . $timeoffset) : $timeoffset
		);
		$this->timezone_set($timeoffset);

		$this->var['formhash'] = formhash();
		define('FORMHASH', $this->var['formhash']);

		if ($this->init_user) {
			//拒绝访问
			if ($this->var['group'] && isset($this->var['group']['allowvisit']) && !$this->var['group']['allowvisit']) {
				if ($this->var['uid']) {
					bannedmsg('Sorry, you can not access the site!');
				} elseif ((!defined('ALLOWGUEST') || !ALLOWGUEST) && !$this->var['inajax']) {
					dheader('location: index.php?option=member&task=login&referer=' . rawurlencode($_SERVER['REQUEST_URI']));
				}
			}
			if ($this->var['member']['status'] == -1) {
				bannedmsg('Sorry, you can not access the site!');
			}
		}

		if ($this->var['setting']['ipaccess'] && !ipaccess($this->var['clientip'], $this->var['setting']['ipaccess'])) {
			bannedmsg('Sorry, you can not access the site!');
		}

		if ($this->var['setting']['siteclosed']) {
			if ($this->var['uid'] && ($this->var['group']['allowvisit'] == 2 || $this->var['groupid'] == 1)) {

			} elseif (in_array(CURSCRIPT, array('admin', 'member', 'misc', 'api')) && !defined('CLOSEBANNED')) {

			} else {
				$closedreason = DB::result_first("SELECT svalue FROM #__common_setting WHERE skey='closedreason'");
				$closedreason = str_replace(':', '&#58;', $closedreason);
				showmessage($closedreason ? $closedreason : 'This site is closed!', NULL, array(), array('login' => 1));
			}
		}

		if ($this->var['setting']['nocacheheaders']) {
			@header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" );
			@header( "Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT" );
			@header( "Cache-Control: no-store, private, post-check=0, pre-check=0, max-age=0", FALSE);
			@header( "Cache-Control: no-store, no-cache, must-revalidate" );
			@header("Pragma: no-cache");
		}

		if ($this->session->isnew && $this->var['uid']) {
			updatecreditbyaction('daylogin', $this->var['uid']);
		}

		$lastact = TIMESTAMP . "\t" . htmlspecialchars(basename($this->var['PHP_SELF'])) . "\t" . htmlspecialchars($this->var['task']);
		dsetcookie('lastact', $lastact, 86400);
		setglobal('currenturl_encode', base64_encode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']));

		$this->var['seokeywords'] = !empty($this->var['setting']['seokeywords'][CURSCRIPT]) ? $this->var['setting']['seokeywords'][CURSCRIPT] : '';
		$this->var['seodescription'] = !empty($this->var['setting']['seodescription'][CURSCRIPT]) ? $this->var['setting']['seodescription'][CURSCRIPT] : '';
	}

	/**
	 * 初始化系统设置
	 */
	function _init_setting() {
		global $_G;
		if ($this->init_setting) {
			if (empty($this->var['setting'])) {
				$this->cachelist[] = 'setting';
			}

			if (empty($this->var['style'])) {
				$this->cachelist[] = 'style_default';
			}

			if (!isset($this->var['cache']['cronnextrun'])) {
				$this->cachelist[] = 'cronnextrun';
			}
		}
		!empty($this->cachelist) && loadcache($this->cachelist);
		if(!$_G['setting']['attachurl']) $_G['setting']['attachurl'] = 'data/attachment/';
		if (!is_array($this->var['setting'])) {
			$this->var['setting'] = (array)$_G['setting'];
		}

		if (!$this->var['uid']) {
			//新注册用户组ID
			loadcache('usergroup_10');
		}

		if ($this->var['member'] && $this->var['group']['radminid'] == 0 && $this->var['member']['adminid'] > 0 && $this->var['member']['groupid'] != $this->var['member']['adminid'] && !empty($this->var['cache']['admingroup_' . $this->var['member']['adminid']])) {
			$this->var['group'] = array_merge($this->var['group'], $this->var['cache']['admingroup_' . $this->var['member']['adminid']]);
		}
	}

	function _init_style() {
		global $_G;
		$styleid = !empty($this->var['cookie']['styleid']) ? $this->var['cookie']['styleid'] : 0;

		if (!defined('STYLEID') || !constant('STYLEID')) {
			//include_once libfile('function/cache');
			//updatecache('styles');
			define('STYLEID', $_G['setting']['styleid']);
		}
		if ($styleid && $styleid != $this->var['setting']['styleid']) {
			loadcache('style_' . $styleid);
			if ($this->var['cache']['style_' . $styleid]) {
				$this->var['style'] = $this->var['cache']['style_' . $styleid];
			}
			$this->var['group']['allowdiy'] = 0;
		}

		if (is_array($this->var['style'])) {
			foreach ($this->var['style'] as $key => $val) {
				$key = strtoupper($key);
				if (!defined($key) && !is_array($val)) {
					define($key, $val);
				}
			}
		}
	}

	function timezone_set($timeoffset = 0) {
		if (function_exists('date_default_timezone_set')) {
			@date_default_timezone_set('Etc/GMT' . ($timeoffset > 0 ? '-' : '+') . (abs($timeoffset)));
		}
	}

}

class db_mysql {

	var $tablepre;
	var $version = '';
	var $querynum = 0;
	var $curlink;
	var $link = array();
	var $config = array();
	var $sqldebug = array();
	var $qid;
	var $goneway = 0;

	function db_mysql($config = array()) {
		if (!empty($config)) {
			$this->set_config($config);
		}
	}

	function set_config($config) {
		$this->config = &$config;
		$this->tablepre = $config['tablepre'];
	}

	function connect() {

		if (empty($this->config)) {
			$this->halt('config_db_not_found');
		}

		$this->link = $this->_dbconnect(
						$this->config['dbhost'],
						$this->config['dbuser'],
						$this->config['dbpw'],
						$this->config['dbcharset'],
						$this->config['dbname'],
						$this->config['pconnect']
		);
		$this->curlink = $this->link;
	}

	function _dbconnect($dbhost, $dbuser, $dbpw, $dbcharset, $dbname, $pconnect) {
		$link = null;
		$func = empty($pconnect) ? 'mysql_connect' : 'mysql_pconnect';
		if (!$link = @$func($dbhost, $dbuser, $dbpw, 1)) {
			if($this->goneway<5){
				$this->goneway++;
				$this->connect();
				exit;
			}
			$this->halt('notconnect');
		} else {
			$this->curlink = $link;
			if ($this->version() > '4.1') {
				$dbcharset = $dbcharset ? $dbcharset : $this->config['dbcharset'];
				$serverset = $dbcharset ? 'character_set_connection=' . $dbcharset . ', character_set_results=' . $dbcharset . ', character_set_client=binary' : '';
				$serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',') . 'sql_mode=\'\'') : '';
				$serverset && mysql_query("SET $serverset", $link);
			}
			$dbname && @mysql_select_db($dbname, $link);
		}
		return $link;
	}

	function select_db($dbname) {
		return mysql_select_db($dbname, $this->curlink);
	}

	function fetch_array($query, $result_type = MYSQL_ASSOC) {
		if(!$query) $query = $this->qid;
		return mysql_fetch_array($query, $result_type);
	}

	function fetch_first($sql) {
		return $this->fetch_array($this->query($sql));
	}

	function result_first($sql) {
		return $this->result($this->query($sql), 0);
	}

	function getEscaped( $text, $extra = false ) {
		$string = mysqli_real_escape_string( $this->_resource, $text );
		if ($extra) {
			$string = addcslashes( $string, '%_' );
		}
		return $string;
	}
	function Quote( $text, $escaped = false ) {
		return '\''.($escaped ? $this->getEscaped( $text ) : $text).'\'';
	}
	function NameQuote( $s ) {
		$q = '`';
		if (strlen( $q ) == 1) {
			return $q . $s . $q;
		} else {
			return $q{0} . $s . $q{1};
		}
	}
	function _quoteField( $value, $type ) {
		switch ($type) {
			case 'text':
			case 'mediumtext':
			case 'varchar':
				$result = $this->Quote( $value );
				break;

			case 'date':
			case 'datetime':
				if (empty( $value )) {
					$value = $this->_nullDate;
				}
				$result = $this->Quote( $value );
				break;

			case 'float':
			case 'double':
				$result = (double) $value;
				break;

			case 'int':
			case 'tinyint':
			case 'tinyint unsigned':
			case 'int unsigned':
			case 'unsigned':
			default:
				//$result = (int) $value;
				$result = $this->Quote($value);
				break;
		}
		return $result;
	}
	/**
	 * @param array A list of valid (and safe!) table names
	 * @return array An array of fields by table
	 */
	function getTableFields( $tables ) {
		$result = array();
		foreach ($tables as $tblval) {
			$this->Query( 'SHOW FIELDS FROM ' . $tblval );
			$fields = $this->loadlist();
			foreach ($fields as $field) {
				$result[$tblval][$field['Field']] = preg_replace("/[(0-9)]/",'', $field['Type'] );
			}
		}
		return $result;
	}
	function loadlist($query=0){
		if(!$query)$query=$this->qid;
		$rows=array();
		while($result=$this->fetch_array($query)){
			$rows[]=$result;
		}
		return $rows;
	}
	function query($sql, $type = '') {
		global $_G;
		$tablepre = $_G['config']['db']['tablepre'];
		$pre = '@#__([a-z0-9_]+)@i';
		$sql = preg_replace($pre, $tablepre.'\\1', $sql);
		$sql = preg_replace('/\s+AND\s+ORDER/isU', ' ORDER', $sql);
		if (defined('CMS_DEBUG') && CMS_DEBUG) {
			$starttime = dmicrotime();
		}
		$func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ?
				'mysql_unbuffered_query' : 'mysql_query';
		if (!($query = $func($sql, $this->curlink))) {
			if (in_array($this->errno(), array(2003, 2006, 2013)) && substr($type, 0, 5) != 'RETRY') {
				$this->connect();
				return $this->query($sql, 'RETRY' . $type);
			}
			if($this->errno()==2003 && $this->goneway<5){
				$this->goneway++;
				$this->connect();
				return $this->query($sql, $type);
			}
			if ($type != 'SILENT' && substr($type, 5) != 'SILENT') {
				$this->halt('query_error', $sql);
			}
		}

		if (defined('CMS_DEBUG') && CMS_DEBUG) {
			$this->sqldebug[] = array($sql, number_format((dmicrotime() - $starttime), 6), debugmessage(basename(__FILE__), __LINE__));
		}

		$this->querynum++;
		$this->qid = $query;
		return $query;
	}

	function affected_rows() {
		return mysql_affected_rows($this->curlink);
	}

	function error() {
		return (($this->curlink) ? mysql_error($this->curlink) : mysql_error());
	}

	function errno() {
		return intval(($this->curlink) ? mysql_errno($this->curlink) : mysql_errno());
	}

	function result($query, $row = 0) {
		if(!$query) $query = $this->qid;
		$query = @mysql_result($query, $row);
		return $query;
	}

	function num_rows($query) {
		if(!$query) $query = $this->qid;
		$query = mysql_num_rows($query);
		return $query;
	}

	function num_fields($query) {
		if(!$query) $query = $this->qid;
		return mysql_num_fields($query);
	}

	function free_result($query) {
		if(!$query) $query = $this->qid;
		return mysql_free_result($query);
	}

	function insert_id() {
		return ($id = mysql_insert_id($this->curlink)) >= 0 ? $id : $this->result($this->query("SELECT last_insert_id()"), 0);
	}

	function fetch_row($query) {
		if(!$query) $query = $this->qid;
		$query = mysql_fetch_row($query);
		return $query;
	}

	function fetch_fields($query) {
		if(!$query) $query = $this->qid;
		return mysql_fetch_field($query);
	}

	function version() {
		if (empty($this->version)) {
			$this->version = mysql_get_server_info($this->curlink);
		}
		return $this->version;
	}

	function close() {
		return mysql_close($this->curlink);
	}

	function halt($message = '', $sql = '') {
		require_once libfile('class/error');
		$message = str_replace($this->config['dbname'].'.', '', $message);
		cmsError::db_error($message, $sql);
	}

}

class DB {

	static function affected_rows() {
		return DB::_execute('affected_rows');
	}

	static function checkquery($sql) {
		static $status = null, $checkcmd = array('SELECT', 'UPDATE', 'INSERT', 'REPLACE', 'DELETE');
		if ($status === null)
			$status = getglobal('config/security/querysafe/status');
		if ($status) {
			$cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));
			if (in_array($cmd, $checkcmd)) {
				$test = DB::_do_query_safe($sql);
				if ($test < 1)
					DB::_execute('halt', 'security_error', $sql);
			}
		}
		return true;
	}
	static function getWhereSQL($wheresqlarr = array()){
		$result = $comma = '';
		if($wheresqlarr) {
			$result = ' WHERE ';
			if(is_array($wheresqlarr)) {
				foreach ($wheresqlarr as $key => $value) {
					$result .= $comma.'`'.$key.'`=\''.$value.'\'';
					$comma = ' AND ';
				}
			} else {
				$result .= $wheresqlarr;
			}
		}
		return $result;
	}
	static function select($tablename, $fields = array(), $wheresqlarr = array(), $plussql='') {
		global $_G;
		$tablepre = $_G['config']['db']['tablepre'];
		$tl = strlen($tablepre);
		if(substr($tablename, 0, $tl)!=$tablepre) $tablename = '#__' . $tablename;
		$sql = "SELECT ";
		$selectsql = $comma = '';
		if($fields){
			if(is_array($fields)){
				$sql .= implode(', ', $fields);
			} else {
				$sql .= $fields;
			}
		} else {
			$sql = '*';
		}
		$results = array();
		DB::query($sql.' FROM '.$tablename.DB::getwheresql($wheresqlarr).' '.$plussql);
		return DB::fetch_all();
	}
	/**
	 * 删除指定表中的记录
	 *
	 * @param string $table 表名
	 * @param array/string $condition 条件
	 * @param int $limit 要删除的记录数
	 * @param boolean $unbuffered 是否缓冲
	 * @return boolean 是否删除成功
	 */
	static function delete($table, $condition, $limit = 0, $unbuffered = true) {
		if (empty($condition)) {
			$where = '1';
		} elseif (is_array($condition)) {
			$where = DB::implode_field_value($condition, ' AND ');
		} else {
			$where = $condition;
		}
		$sql = "DELETE FROM #__$table WHERE $where " . ($limit ? "LIMIT $limit" : '');
		return DB::query($sql, ($unbuffered ? 'UNBUFFERED' : ''));
	}
	/**
	 * @param array A list of valid (and safe!) table names
	 * @return array An array of fields by table
	 */
	function getTableFields( $tables ) {
		$result = array();
		foreach ($tables as $tblval) {
			DB::Query( 'SHOW FIELDS FROM ' . $tblval );
			$fields = DB::fetch_all();
			foreach ($fields as $field) {
				$result[$tblval][$field['Field']] = preg_replace("/[(0-9)]/",'', $field['Type'] );
			}
		}
		return $result;
	}
	static function errno() {
		return DB::_execute('errno');
	}

	static function error() {
		return DB::_execute('error');
	}

	static function fetch($resourceid = '', $type = MYSQL_ASSOC) {
		return DB::_execute('fetch_array', $resourceid, $type);
	}

	static function fetch_all($resourceid = '', $key = '') {
		if(is_string($resourceid) && $resourceid){
			$resourceid = DB::query($resourceid);
		}
		$rows = array();
		while ($row = DB::_execute('fetch_array', $resourceid, MYSQL_ASSOC)) {
			if($key && isset($row[$key])) $k = $row[$key];
			else $k = '';
			if($k)
			$rows[$k] = $row;
			else
				$rows[] = $row;
		}
		return $rows;
	}

	static function fetch_array($resourceid = '', $type = MYSQL_ASSOC) {
		return DB::_execute('fetch_array', $resourceid, $type);
	}

	static function fetch_first($sql) {
		DB::checkquery($sql);
		return DB::_execute('fetch_first', $sql);
	}

	static function free_result($query) {
		return DB::_execute('free_result', $query);
	}

	static function implode_field_value($array, $glue = ',') {
		$sql = $comma = '';
		foreach ($array as $k => $v) {
			if(!$v && $v!='0') $v = '';
			if($v=='utf-8' || $v=='UTF-8')
				$tv="'$v'";
			else {
			$tv = preg_replace('/[a-z\s\t]+[\-\+][0-9\s\t]+/i', '', $v);
			if($tv){
				$tv = preg_replace('/[0-9\s\t]+[\-\+][a-z\s\t]+/i', '', $v);
				if($tv)	$tv = "'$v'";
				else $tv = $v;
			}
			else $tv = $v;
			}
			if(!$tv) $tv = "'$tf'";
			$sql .= $comma . "`$k`=$tv";
			$comma = $glue;
		}
		return $sql;
	}

	/**
	 *
	 * @param string $table 表名
	 * @param array $data 值
	 * @param boolean $return_insert_id 是否需要返回插入的ID
	 * @param <type> $replace
	 * @param <type> $silent
	 * @return <type>
	 */
	static function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {
		$sql = DB::implode_field_value($data);
		$cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
		$silent = $silent ? 'SILENT' : '';
		$return = DB::query("$cmd #__$table SET $sql", $silent);
		return $return_insert_id ? DB::insert_id() : $return;
	}

	static function insert_id() {
		return DB::_execute('insert_id');
	}

	static function num_rows($resourceid='') {
		return DB::_execute('num_rows', $resourceid);
	}

	static function &object() {
		global $db;
		if (empty($db)) $db = new db_mysql();
		return $db;
	}

	static function query($sql, $type = '') {
		DB::checkquery($sql);
		return DB::_execute('query', $sql, $type);
	}

	static function result($resourceid = '', $row = 0) {
		return DB::_execute('result', $resourceid, $row);
	}

	static function result_first($sql) {
		DB::checkquery($sql);
		return DB::_execute('result_first', $sql);
	}

	/**
	 *
	 * @param string $table 表名
	 * @param array $data 字段和值
	 * @param string/array $condition 条件
	 * @param <type> $unbuffered
	 * @param <type> $low_priority
	 * @return <type>
	 */
	static function update($table, $data, $condition, $unbuffered = false, $low_priority = false) {
		$sql = DB::implode_field_value($data);
		$cmd = "UPDATE " . ($low_priority ? 'LOW_PRIORITY' : '');
		$where = '';
		if (empty($condition)) {
			$where = '1';
		} elseif (is_array($condition)) {
			$where = DB::implode_field_value($condition, ' AND ');
		} else {
			$where = $condition;
		}
		$res = DB::query("$cmd #__$table SET $sql WHERE $where", $unbuffered ? 'UNBUFFERED' : '');
		return $res;
	}

	function _do_query_safe($sql) {
		global $_G;
		$tablepre = $_G['config']['db']['tablepre'];
		static $_CONFIG = null;
		if ($_CONFIG === null) {
			$_CONFIG = getglobal('config/security/querysafe');
		}

		$sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);
		$pre = '@#__([a-z0-9_]+)@i';

		$sql = preg_replace($pre, $tablepre.'\\1', $sql);
		$mark = $clean = '';
		if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {
			$clean = preg_replace("/'(.+?)'/s", '', $sql);
		} else {
			$len = strlen($sql);
			$mark = $clean = '';
			for ($i = 0; $i < $len; $i++) {
				$str = $sql[$i];
				switch ($str) {
					case '\'':
						if (!$mark) {
							$mark = '\'';
							$clean .= $str;
						} elseif ($mark == '\'') {
							$mark = '';
						}
						break;
					case '/':
						if (empty($mark) && $sql[$i + 1] == '*') {
							$mark = '/*';
							$clean .= $mark;
							$i++;
						} elseif ($mark == '/*' && $sql[$i - 1] == '*') {
							$mark = '';
							$clean .= '*';
						}
						break;
					case '#':
						if (empty($mark)) {
							$mark = $str;
							$clean .= $str;
						}
						break;
					case "\n":
						if ($mark == '#' || $mark == '--') {
							$mark = '';
						}
						break;
					case '-':
						if (empty($mark) && substr($sql, $i, 3) == '-- ') {
							$mark = '-- ';
							$clean .= $mark;
						}
						break;

					default:

						break;
				}
				$clean .= $mark ? '' : $str;
			}
		}

		$clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));

		if ($_CONFIG['afullnote']) {
			$clean = str_replace('/**/', '', $clean);
		}

		if (is_array($_CONFIG['dfunction'])) {
			foreach ($_CONFIG['dfunction'] as $fun) {
				if (strpos($clean, $fun . '(') !== false)
					return '-1';
			}
		}

		if (is_array($_CONFIG['daction'])) {
			foreach ($_CONFIG['daction'] as $action) {
				if (strpos($clean, $action) !== false)
					return '-3';
			}
		}

		if ($_CONFIG['dlikehex'] && strpos($clean, 'like0x')) {
			return '-2';
		}

		if (is_array($_CONFIG['dnote'])) {
			foreach ($_CONFIG['dnote'] as $note) {
				if (strpos($clean, $note) !== false)
					return '-4';
			}
		}

		return 1;
	}

	static function _execute($cmd, $arg1 = '', $arg2 = '') {
		global $db;
		if (empty($db)) $db = new db_mysql();
		$res = $db->$cmd($arg1, $arg2);
		return $res;
	}

}

class cmsSession {

	var $sid = null;
	var $var = null;
	var $isnew = false;
	var $newguest = array('sid' => 0, 'ip1' => 0, 'ip2' => 0, 'ip3' => 0, 'ip4' => 0,
		'uid' => 0, 'username' => '', 'groupid' => 7, 'action' => 0,
		'lastactivity' => 0);
	var $old = array('sid' => '', 'ip' => '', 'uid' => 0);

	function cmsSession($sid = '', $ip = '', $uid = 0) {
		$this->old = array('sid' => $sid, 'ip' => $ip, 'uid' => $uid);
		$this->var = $this->newguest;
		if (!empty($ip)) {
			$this->init($sid, $ip, $uid);
		}
	}

	function set($key, $value) {
		if (isset($this->newguest[$key])) {
			$this->var[$key] = $value;
		} elseif ($key == 'ip') {
			$ips = explode('.', $value);
			$this->set('ip1', $ips[0]);
			$this->set('ip2', $ips[1]);
			$this->set('ip3', $ips[2]);
			$this->set('ip4', $ips[3]);
		}
	}

	function get($key) {
		if (isset($this->newguest[$key])) {
			return $this->var[$key];
		} elseif ($key == 'ip') {
			return $this->get('ip1') . '.' . $this->get('ip2') . '.' . $this->get('ip3') . '.' . $this->get('ip4');
		}
	}

	function init($sid, $ip, $uid) {
		$this->old = array('sid' => $sid, 'ip' => $ip, 'uid' => $uid);
		$session = array();
		if ($sid) {
			$session = DB::fetch_first("SELECT * FROM #__common_session" .
							" WHERE sid='$sid' AND CONCAT_WS('.', ip1,ip2,ip3,ip4)='$ip'");
		}

		if (empty($session) || $session['uid'] != $uid) {
			$session = $this->create($ip, $uid);
		}

		$this->var = $session;
		$this->sid = $session['sid'];
	}

	function create($ip, $uid) {

		$this->isnew = true;
		$this->var = $this->newguest;
		$this->set('sid', random(6));
		$this->set('uid', $uid);
		$this->set('ip', $ip);
		$this->set('lastactivity', time());
		$this->sid = $this->var['sid'];

		return $this->var;
	}

	function delete() {

		global $_G;
		$onlinehold = $_G['setting']['onlinehold'];
		$guestspan = 60;

		$onlinehold = time() - $onlinehold;
		$guestspan = time() - $guestspan;

		$condition = " sid='{$this->sid}' ";
		$condition .= " OR lastactivity<$onlinehold ";
		$condition .= " OR (uid='0' AND ip1='{$this->var['ip1']}' AND ip2='{$this->var['ip2']}' AND ip3='{$this->var['ip3']}' AND ip4='{$this->var['ip4']}' AND lastactivity>$guestspan) ";
		$condition .= $this->var['uid'] ? " OR (uid='{$this->var['uid']}') " : '';
		DB::delete('common_session', $condition);
	}

	function update() {
		if ($this->sid !== null) {
			$data = daddslashes($this->var);
			if ($this->isnew) {
				$this->delete();
				DB::insert('common_session', $data, false, false, true);
			} else {
				DB::update('common_session', $data, "sid='$data[sid]'");
			}
			dsetcookie('sid', $this->sid, 86400);
		}
	}

	function onlinecount($type = 0) {
		$condition = $type == 1 ? ' WHERE uid>0 ' : '';
		return DB::result_first("SELECT count(*) FROM #__common_session $condition");
	}

}

class cmsCron {

	/**
	 * 执行指定的计划任务
	 *
	 * @param int $cronid 计划任务ID
	 * @return boolean 是否执行成功
	 */
	function run($cronid = 0) {

		global $_G;
		$timestamp = TIMESTAMP;
		$cron = DB::fetch_first("SELECT * FROM #__common_cron
				WHERE " . ($cronid ? "cronid='$cronid'" : "available>'0' AND nextrun<='$timestamp'") . "
				ORDER BY nextrun LIMIT 1");

		$processname = 'DZ_CRON_' . (empty($cron) ? 'CHECKER' : $cron['cronid']);

		if ($cronid && !empty($cron)) {
			cmsProcess::unlock($processname);
		}

		if (cmsProcess::islocked($processname, 600)) {
			return false;
		}

		if ($cron) {
			$cron['filename'] = str_replace(array('..', '/', '\\'), '', $cron['filename']);
			$cronfile = ROOT_PATH . './source/cron/' . $cron['filename'];

			$cron['minute'] = explode("\t", $cron['minute']);
			cmsCron::setnextime($cron);

			@set_time_limit(1000);
			@ignore_user_abort(TRUE);
			if (!@include $cronfile) {
				return false;
			}
		}

		cmsCron::nextcron();
		cmsProcess::unlock($processname);
		return true;
	}

	/**
	 * 设定下次执行时间
	 *
	 * @return 无
	 */
	function nextcron() {
		$nextrun = DB::result_first("SELECT nextrun FROM #__common_cron WHERE available>'0' ORDER BY nextrun LIMIT 1");
		require_once libfile('function/cache');
		if ($nextrun !== FALSE) {
			save_syscache('cronnextrun', $nextrun);
		} else {
			save_syscache('cronnextrun', TIMESTAMP + 86400 * 365);
		}
	}

	/**
	 * 设置指定的计划任务的下次执行时间
	 *
	 * @param array $cron 指定的计划任务
	 * @return 无
	 */
	function setnextime($cron) {
		global $_G;
		if (empty($cron))
			return FALSE;

		list($yearnow, $monthnow, $daynow, $weekdaynow, $hournow, $minutenow) = explode('-', gmdate('Y-m-d-w-H-i', TIMESTAMP + $_G['setting']['timeoffset'] * 3600));

		if ($cron['weekday'] == -1) {
			if ($cron['day'] == -1) {
				$firstday = $daynow;
				$secondday = $daynow + 1;
			} else {
				$firstday = $cron['day'];
				$secondday = $cron['day'] + gmdate('t', TIMESTAMP + $_G['setting']['timeoffset'] * 3600);
			}
		} else {
			$firstday = $daynow + ($cron['weekday'] - $weekdaynow);
			$secondday = $firstday + 7;
		}

		if ($firstday < $daynow) {
			$firstday = $secondday;
		}

		if ($firstday == $daynow) {
			$todaytime = cmsCron::todaynextrun($cron);
			if ($todaytime['hour'] == -1 && $todaytime['minute'] == -1) {
				$cron['day'] = $secondday;
				$nexttime = cmsCron::todaynextrun($cron, 0, -1);
				$cron['hour'] = $nexttime['hour'];
				$cron['minute'] = $nexttime['minute'];
			} else {
				$cron['day'] = $firstday;
				$cron['hour'] = $todaytime['hour'];
				$cron['minute'] = $todaytime['minute'];
			}
		} else {
			$cron['day'] = $firstday;
			$nexttime = cmsCron::todaynextrun($cron, 0, -1);
			$cron['hour'] = $nexttime['hour'];
			$cron['minute'] = $nexttime['minute'];
		}

		$nextrun = @gmmktime($cron['hour'], $cron['minute'] > 0 ? $cron['minute'] : 0, 0, $monthnow, $cron['day'], $yearnow) - $_G['setting']['timeoffset'] * 3600;

		$availableadd = $nextrun > TIMESTAMP ? '' : ', available=\'0\'';
		DB::query("UPDATE #__common_cron SET lastrun='$_G[timestamp]', nextrun='$nextrun' $availableadd WHERE cronid='$cron[cronid]'");
	}

	function todaynextrun($cron, $hour = -2, $minute = -2) {
		global $_G;

		$hour = $hour == -2 ? gmdate('H', TIMESTAMP + $_G['setting']['timeoffset'] * 3600) : $hour;
		$minute = $minute == -2 ? gmdate('i', TIMESTAMP + $_G['setting']['timeoffset'] * 3600) : $minute;

		$nexttime = array();
		if ($cron['hour'] == -1 && !$cron['minute']) {
			$nexttime['hour'] = $hour;
			$nexttime['minute'] = $minute + 1;
		} elseif ($cron['hour'] == -1 && $cron['minute'] != '') {
			$nexttime['hour'] = $hour;
			if (($nextminute = cmsCron::nextminute($cron['minute'], $minute)) === false) {
				++$nexttime['hour'];
				$nextminute = $cron['minute'][0];
			}
			$nexttime['minute'] = $nextminute;
		} elseif ($cron['hour'] != -1 && $cron['minute'] == '') {
			if ($cron['hour'] < $hour) {
				$nexttime['hour'] = $nexttime['minute'] = -1;
			} elseif ($cron['hour'] == $hour) {
				$nexttime['hour'] = $cron['hour'];
				$nexttime['minute'] = $minute + 1;
			} else {
				$nexttime['hour'] = $cron['hour'];
				$nexttime['minute'] = 0;
			}
		} elseif ($cron['hour'] != -1 && $cron['minute'] != '') {
			$nextminute = cmsCron::nextminute($cron['minute'], $minute);
			if ($cron['hour'] < $hour || ($cron['hour'] == $hour && $nextminute === false)) {
				$nexttime['hour'] = -1;
				$nexttime['minute'] = -1;
			} else {
				$nexttime['hour'] = $cron['hour'];
				$nexttime['minute'] = $nextminute;
			}
		}

		return $nexttime;
	}

	function nextminute($nextminutes, $minutenow) {
		foreach ($nextminutes as $nextminute) {
			if ($nextminute > $minutenow) {
				return $nextminute;
			}
		}
		return false;
	}

}

class cmsProcess {

	function islocked($process, $ttl = 0) {
		$ttl = $ttl < 1 ? 600 : intval($ttl);
		if (cmsProcess::_status('get', $process)) {
			return true;
		} else {
			return cmsProcess::_find($process, $ttl);
		}
	}

	function unlock($process) {
		cmsProcess::_status('rm', $process);
		cmsProcess::_cmd('rm', $process);
	}

	function _status($action, $process) {
		static $plist = array();
		switch ($action) {
			case 'set' : $plist[$process] = true;
				break;
			case 'get' : return!empty($plist[$process]);
				break;
			case 'rm' : $plist[$process] = null;
				break;
			case 'clear' : $plist = array();
				break;
		}
		return true;
	}

	function _find($name, $ttl) {

		if (!cmsProcess::_cmd('get', $name)) {
			cmsProcess::_cmd('set', $name, $ttl);
			$ret = false;
		} else {
			$ret = true;
		}
		cmsProcess::_status('set', $name);
		return $ret;
	}

	function _cmd($cmd, $name, $ttl = 0) {
		$ret = '';
		switch ($cmd) {
			case 'set':
				$ret = DB::insert('common_process', array('processid' => $name, 'expiry' => time() + $ttl), false, true);
				break;
			case 'get':
				$ret = DB::fetch_first("SELECT * FROM #__common_process WHERE processid='$name'");
				if (empty($ret) || $ret['expiry'] < time()) {
					$ret = false;
				} else {
					$ret = true;
				}
				break;
			case 'rm':
				$ret = DB::delete('common_process', "processid='$name' OR expiry<" . time());
				break;
		}
		return $ret;
	}

}
@ini_set('display_errors', 1);
